package top.szhome.framework.starter.db.wrapper;

import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.util.ReflectionUtils;
import top.szhome.framework.core.tools.annotation.db.Order;
import top.szhome.framework.core.tools.annotation.db.Where;
import top.szhome.framework.core.tools.constant.Condition;
import top.szhome.framework.core.tools.util.ObjectUtil;

import java.util.*;

/**
 * 自动包装查询条件
 *
 * @author 唐加利
 * @date 2023/6/11
 **/
public class AutoQueryWrapper<T> extends QueryWrapper<T> {

    /**
     * 查询条件
     */
    private Object condition;

    /**
     * 构造自动组装查询条件
     * @param condition
     */
    public AutoQueryWrapper(Object condition) {
        super();
        this.condition = condition;
        build();
    }

    public AutoQueryWrapper(Object condition, String... columns) {
        super(null, columns);
        this.condition = condition;
        build();
    }


    /**
     * 构建查询条件
     */
    public void build() {
        final QueryWrapper<T> wrapper = this;
        // 查询条件
        ReflectionUtils.doWithFields(this.condition.getClass(), field -> {
            field.setAccessible(true);

            // 对应字段
            Where where = field.getAnnotation(Where.class);
            String column = where.column();
            if(StringUtils.isBlank(column)){
                column = field.getName().replaceAll("([A-Z])", "_$1").toLowerCase();
            }

            Object value = field.get(this.condition);
            Condition condition = where.value();

            CONSUMERS.get(condition).and(AutoQueryWrapper.this, column, value);
        }, field -> AnnotatedElementUtils.hasAnnotation(field, Where.class));

        // 处理排序
        Map<Order, String> sorts = new TreeMap<>(Comparator.comparingInt(Order::order));
        ReflectionUtils.doWithFields(this.condition.getClass(),field -> {
            Order order = AnnotatedElementUtils.findMergedAnnotation(field, Order.class);
            String column = order.column();
            if(StringUtils.isBlank(column)){
                column = field.getName().replaceAll("([A-Z])", "_$1").toLowerCase();
            }
            sorts.put(order, column);
        } ,  field -> AnnotatedElementUtils.hasAnnotation(field, Order.class));
        sorts.forEach((order, column) -> this.orderBy(true, order.asc(), column));
    }

    /**
     * 查询条件与实现映射
     */
    private static Map<Condition, ConditionConsumer> CONSUMERS = new HashMap<>();
    static {
        CONSUMERS.put(Condition.EQ, (wrapper, column, value) -> {
            if(ObjectUtil.isEmpty(value)){
                return;
            }
            wrapper.eq(column, value);
        });

        CONSUMERS.put(Condition.NE, (wrapper, column, value) -> {
            if(ObjectUtil.isEmpty(value)){
                return;
            }
            wrapper.ne(column, value);
        });
        CONSUMERS.put(Condition.GT, (wrapper, column, value) -> {
            if(ObjectUtil.isEmpty(value)){
                return;
            }
            wrapper.gt(column, value);
        });;

        CONSUMERS.put(Condition.GE, (wrapper, column, value) -> {
            if(ObjectUtil.isEmpty(value)){
                return;
            }
            wrapper.ge(column, value);
        });;

        CONSUMERS.put(Condition.LT, (wrapper, column, value) -> {
            if(ObjectUtil.isEmpty(value)){
                return;
            }
            wrapper.lt(column, value);
        });;

        CONSUMERS.put(Condition.LE, (wrapper, column, value) -> {
            if(ObjectUtil.isEmpty(value)){
                return;
            }
            wrapper.le(column, value);
        });;

        CONSUMERS.put(Condition.LIKE, (wrapper, column, value) ->
        {
            if(ObjectUtil.isEmpty(value)){
                return;
            }
            wrapper.like(column, value.toString().replaceAll("([_%\\\\])", "\\\\$1"));
        });

        CONSUMERS.put(Condition.NOT_LIKE, (wrapper, column, value) -> {
            if(ObjectUtil.isEmpty(value)){
                return;
            }
            wrapper.notLike(column, value.toString().replaceAll("([_%\\\\])", "\\\\$1"));
        });

        CONSUMERS.put(Condition.IN, (wrapper, column, value) -> {
            if(ObjectUtil.isEmpty(value)){
                return;
            }

            Collection collection = value instanceof Collection ? (Collection) value : Arrays.asList(value);
            wrapper.in(column, collection);
        });

        CONSUMERS.put(Condition.NOT_IN, (wrapper, column, value) -> {
            if(ObjectUtil.isEmpty(value)){
                return;
            }

            Collection collection = value instanceof Collection ? (Collection) value : Arrays.asList(value);
            wrapper.notIn(column, collection);
        });

        CONSUMERS.put(Condition.IS_NULL, (wrapper, column, value) -> wrapper.isNull(column));

        CONSUMERS.put(Condition.NOT_NULL, (wrapper, column, value) -> wrapper.isNotNull(column));
    }

    /**
     * 条件消费
     */
    interface ConditionConsumer {

        /**
         * 条件
         * @param wrapper
         * @param column
         * @param value
         */
        void and(AbstractWrapper wrapper, String column, Object value);
    }

}
